package org.papervision3d.core.render.material;
//import flash.utils.Dictionary;
import nme.errors.Error;
import nme.ObjectHash;

import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.core.render.data.RenderSessionData;

/**
 * @Author Ralph Hauwert
 * 
 * <code>MaterialManager</code> (used internally) is a singleton that tracks 
 * all materials. Each time a material is created, the <code>MaterialManager</code> 
 * registers the material for access in the render engine. 
 */
class MaterialManager
{
	private static var instance:MaterialManager;
	private var materials:ObjectHash<MaterialObject3D, Bool>;

	/**
	 * MaterialManager singleton constructor
	 */
	public function new():Void
	{
		if(instance != null){
			throw new Error("Only 1 instance of materialmanager allowed");
		}
		init(); 
	}
	
	/** @private */
	private function init():Void
	{
		materials = new ObjectHash<MaterialObject3D, Bool>();
	}
	
	/** @private */
	private function _registerMaterial(material:MaterialObject3D):Void
	{
		materials.set(material, true);
	
	}
	
	/** @private */
	private function _unRegisterMaterial(material:MaterialObject3D):Void
	{
		//delete materials[material];
		materials.remove(material);
	}
	
	/**
	 * Allows for materials that animate or change (e.g., MovieMaterial) to 
	 * be updated prior to the render
	 * 
	 * @param renderSessionData		the data used in updating the material
	 */
	public function updateMaterialsBeforeRender(renderSessionData:RenderSessionData):Void
	{
		var um:IUpdateBeforeMaterial;
					
		for (m in materials.keys()){
			if(Std.is(m, IUpdateBeforeMaterial)){
				um = untyped m;
				if( um.isUpdateable() )
					um.updateBeforeRender(renderSessionData);
			}
		}
	}
	
	/**
	 * Allows for materials that animate or change (e.g., MovieMaterial) to 
	 * be updated after the render
	 * 
	 * @param renderSessionData		the data used in updating the material
	 */
	public function updateMaterialsAfterRender(renderSessionData:RenderSessionData):Void
	{
		var um:IUpdateAfterMaterial;
		
		for (m in materials.keys()){
			if(Std.is(m, IUpdateAfterMaterial)){
				um = untyped m;
				um.updateAfterRender(renderSessionData);	
			}
		}
	}
	
	/**
	 * Registers a material
	 */
	public static function registerMaterial(material:MaterialObject3D):Void
	{
		getInstance()._registerMaterial(material);
	}
	
	/**
	 * Unregisters a material
	 */
	public static function unRegisterMaterial(material:MaterialObject3D):Void
	{
		getInstance()._unRegisterMaterial(material);
	}
	
	/**
	 * Returns a singleton instance of the <code>MaterialManager</code>
	 */
	public static function getInstance():MaterialManager
	{
		if(instance == null){
			instance = new MaterialManager();
		}
		return instance;
	}
	
}
